﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Viyi.Util.Collections
{
    /// <summary>
    /// 通过索引运算符 <c>[]</c> 添加、修改和获取字典数据，避免异常
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public class DictionaryIndexer<TKey, TValue>
        : IReadOnlyDictionary<TKey, TValue>, IDictionary<TKey, TValue>
    {
        public IDictionary<TKey, TValue> Source { get; }

        public IEnumerable<TKey> Keys => Source.Keys;

        public IEnumerable<TValue> Values => Source.Values;

        public int Count => Source.Count;

        ICollection<TKey> IDictionary<TKey, TValue>.Keys => Source.Keys;

        ICollection<TValue> IDictionary<TKey, TValue>.Values => Source.Values;

        public bool IsReadOnly => Source.IsReadOnly;

        private readonly TValue defaultValue;

        public DictionaryIndexer(IDictionary<TKey, TValue> source,
            TValue defaultValue = default(TValue))
        {
            Source = source ?? throw new ArgumentNullException(nameof(source));
            this.defaultValue = defaultValue;
        }

        public TValue this[TKey key]
        {
            get => Source.TryGetValue(key, out TValue value) ? value : defaultValue;
            set => Source[key] = value;
        }

        public bool ContainsKey(TKey key) => Source.ContainsKey(key);

        public bool TryGetValue(TKey key, out TValue value)
        {
            value = this[key];
            return true;
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => Source.GetEnumerator();

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

        public void Add(TKey key, TValue value) => Source.Add(key, value);

        public bool Remove(TKey key) => Source.Remove(key);

        public void Add(KeyValuePair<TKey, TValue> item) => Source.Add(item);

        public void Clear() => Source.Clear();

        public bool Contains(KeyValuePair<TKey, TValue> item) => Source.Contains(item);

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) => Source.CopyTo(array, arrayIndex);

        public bool Remove(KeyValuePair<TKey, TValue> item) => Source.Remove(item);
    }
}
